﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;

using KSOAdmin.Core.DapperDbContext;
using KSOAdmin.Core.EFDbContext;
using KSOAdmin.Core.Other;
using KSOAdmin.Models.DomainModels.System;
using KSOAdmin.Models.MapperModels;
using KSOAdmin.Models.MapperModels.Enums;
using KSOAdmin.Models.ViewModel;

using log4net;

using Microsoft.AspNetCore.Http;

namespace KSOAdmin.Core.Log
{
    public static class Logging
    {
        //private readonly UserObtain userObtain;
        //this.userObtain = userObtain;
        //private KSOContext Context { get; set; }, KSOContext _Context
        public static ConcurrentQueue<Sys_Log> logs = new ConcurrentQueue<Sys_Log>();
        private static string _loggerPath = AppDomain.CurrentDomain.BaseDirectory + "Logger\\";

        static Logging()
        {
            Task.Run(() => { Start(); });
        }
        public static void Info(string message)
        {
            Info(LoggerType.Info, message);
        }
        public static void Info(LoggerType loggerType, string message = null)
        {
            Info(loggerType, null, message);
        }
        public static void Info(LoggerType loggerType, string resposeParam, string ex = null, int status = 200, bool IsWaritText = false, View_Sys_User userInfo = null)
        {
            Sys_Log log = Add(loggerType, ex, resposeParam, status, userInfo);
            if (IsWaritText)
            {
                 WriteInfo(ex, log.ID, log.Url);
            }
        }

        public static void Error(string message)
        {
            Error(LoggerType.Error, message);
        }
        public static void Error(LoggerType loggerType, string message = null)
        {
            Error(loggerType, null, message);
        }
        public static void Error(LoggerType loggerType, string resposeParam, string ex = null, int status = 500, bool IsWaritText = false, View_Sys_User userInfo = null)
        {
            Sys_Log log = Add(loggerType, ex, resposeParam, status, userInfo);
            if (IsWaritText)
            {
                 WriteInfo(ex, log.ID, log.Url);
            }
        }

        public static void Waring(string message)
        {
            Waring(LoggerType.Waring, message);
        }
        public static void Waring(LoggerType loggerType, string message = null)
        {
            Waring(loggerType, null, message);
        }
        public static void Waring(LoggerType loggerType, string resposeParam, string ex = null, int status = 200, bool IsWaritText = false, View_Sys_User userInfo = null)
        {
            Sys_Log log = Add(loggerType, ex, resposeParam, status, userInfo);
            if (IsWaritText)
            {
                WriteInfo(ex, log.ID, log.Url);
            }
        }

        private static Sys_Log Add(LoggerType loggerType, string ex, string responseParameter, int status, View_Sys_User userInfo = null)
        {
            HttpContext context = KSOHttpContext.Current;
            Sys_Log log = null;
            if (userInfo == null) userInfo = UserObtain.View_Sys_User;

            try
            {
                if (context.Request.Method == "OPTIONS") return null;
                ActionObserver cctionObserver = (context.RequestServices.GetService(typeof(ActionObserver)) as ActionObserver);

                log = new Sys_Log()
                {
                    // ElapsedTime = (int)((cctionObserver.RequestDate - DateTime.Now).TotalMilliseconds),
                    CreateID = userInfo?.ID,
                    Create = userInfo?.UserName,
                    Role_Id = userInfo?.Role_Id,
                    LogType = loggerType.ToString(),
                    ExceptionInfo = ex ?? "正常记录",
                    ResponseParameter = responseParameter ?? "无",
                    Success = status,
                };
                log =  SetServicesInfo(log, context);
            }
            catch (Exception exception)
            {
                log = log ?? new Sys_Log()
                {
                    ElapsedTime = 0,
                    LogType = "日志系统错误：" + loggerType.ToString(),
                    ResponseParameter = responseParameter,
                    ExceptionInfo = ex + "//" + exception.Message,
                    Success = status,
                    CreateID = userInfo.ID,
                    Create = userInfo.UserName,
                };
            }
            logs.Enqueue(log);
            return log;
        }
        public static Sys_Log SetServicesInfo(Sys_Log log, HttpContext context)
        {
            string result = String.Empty;
            log.Url = context.Request.Scheme + "://" + context.Request.Host + context.Request.PathBase +
                context.Request.Path;

            log.UserIP = context.GetUserIp()?.Replace("::ffff:", "");

            log.BrowserType = context.Request.Headers["User-Agent"].ToString();
            if (string.IsNullOrEmpty(log.RequestParameter))
            {
                try
                {
                    log.RequestParameter = context.GetRequestParameters();
                    if (log.RequestParameter != null)
                    {
                        log.RequestParameter = HttpUtility.UrlDecode(log.RequestParameter, Encoding.UTF8);
                    }
                    else
                    {
                        log.RequestParameter = "无法解析";
                    }
                }  
                catch (Exception ex)
                {
                    log.ExceptionInfo += $"日志读取参数出错:{ex.Message}";
                    Console.WriteLine($"日志读取参数出错:{ex.Message}");
                }
            }
            return log;
        }

        public static async void Start()
        {
            List<Sys_Log> logsnew = new List<Sys_Log>();
            while (true)
            {
                //Thread.Sleep(10000);
                if (logs.Count > 0)
                {
                    logsnew.AddRange(logs.ToList());
                    logs.Clear();
                }
                //if (logsnew.Count <20)  continue;
                try
                {
                    if (logsnew.Count > 0)
                    {
                       await  DapperHelp.ExecuteAsync(SplicingSql(logsnew).ToString());
                       //await DapperHelp.AddRange<Sys_Log>(logsnew);
                        logsnew.Clear();
                    }
                }
                catch (Exception ex)
                {
                    WriteError(ex.Message.ToString(), UserObtain.UserId, "");
                    Console.WriteLine($"日志批量写入数据时出错:{ex.Message}");
                    logs.Clear();
                    logsnew.Clear();
                }
            }
        }
        private static StringBuilder SplicingSql(List<Sys_Log> sys_s)
        {
            StringBuilder stringBuilder = new StringBuilder();
            foreach (var item in sys_s)
            {
                stringBuilder.AppendLine($@"INSERT INTO `KSOAdmin`.`Sys_Log` (
                    	                          `BrowserType`,
                    	                          `ElapsedTime`,
                    	                          `ExceptionInfo`,
                    	                          `LogType`,
                    	                          `RequestParameter`,
                    	                          `ResponseParameter`,
                    	                          `Role_Id`,
                    	                          `Url`,
                    	                          `UserIP`,
                    	                          `Create`,
                    	                          `CreateID`,
                    	                          `CreateDate`,
                    	                          `Success`) VALUES 
                                                   ('{item.BrowserType}',
                    	                          	{item.ElapsedTime??0},
                    	                          	'{item.ExceptionInfo}',
                    	                          	'{item.LogType}',
                    	                          	'{item.RequestParameter}',
                    	                          	'{item.ResponseParameter}',
                    	                          	 {item.Role_Id},
                    	                          	'{item.Url}',
                    	                          	'{item.UserIP}',
                    	                          	'{item.Create}',
                    	                          	 {item.CreateID},
                    	                          	 now(),
                    	                          	 {item.Success}  );     ");
            }
            return stringBuilder;
        }

        #region 本地日志
        /// <summary>
        /// 获取日志实例
        /// </summary>
        private static readonly ILog log = LogManager.GetLogger("Logging");

        /// <summary>
        /// 错误日志
        /// </summary>
        /// <param name="msg">自定义消息</param>
        /// <param name="Url">请求的Url : HttpContext.Request.GetAbsoluteUri()</param>
        /// <param name="exp">错误 Exception </param>
        public static void WriteError(object msg, int ID, string Url = "")
        {
            string Msg = string.Empty;
            Msg += ($"\r\n 请求的Url : {Url} \r\n 请求的时间 : {DateTime.UtcNow} \r\n 错误消息 : {msg.ToString()} \r\n ");
            Msg += ($"操作人员 : {ID} \r\n");
            log.Error(Msg);
        }
        /// <summary>
        /// 记录日志
        /// </summary>
        /// <param name="msg">自定义消息</param>
        /// <param name="Url">请求的Url : HttpContext.Request.GetAbsoluteUri()</param>
        public static void WriteInfo(string msg, int ID, string Url = "")
        {
            string Msg = string.Empty;
            Msg += ($"\r\n 请求的Url : {Url} \r\n 请求的时间 : {DateTime.UtcNow} \r\n 记录消息 : {msg.ToString()} ");
            Msg += ($"\r\n");
            log.Info(Msg);
        }
        /// <summary>
        /// 警告日志
        /// </summary>
        /// <param name="msg">自定义消息</param>
        /// <param name="Url">请求的Url : HttpContext.Request.GetAbsoluteUri()</param>
        /// <param name="exp">错误 Exception </param>
        public static void WriteWarn(string msg, string Url = "", string exp = null)
        {
            string Msg = ($"\r\n请求的Url : {Url} \r\n 请求的时间 : {DateTime.UtcNow} \r\n 警告消息 : {msg.ToString()} ");
            if (exp != null)
                Msg += ($"系统警告消息 : {exp} ");
            Msg += ($"\r\n");
            log.Warn(Msg);
        }
        #endregion

    }
}
